home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v10n12.arc / DPMI.C < prev    next >
Text File  |  1991-05-30  |  8KB  |  255 lines

  1. /* 
  2. DPMI.C -- DPMI functions, plus some undocumented Windows functions that
  3. provide the same functionality, plus several layers of "sugar coating"
  4. on top of these low-level services, to make them palatable
  5.  
  6. Copyright (c) 1991 Ziff Communications Co.
  7.     PC Magazine * Andrew Schulman
  8. */
  9.  
  10. #include <windows.h>
  11. #include <dos.h>
  12. #include "dpmi.h"
  13.  
  14. #define MAKEP(seg, ofs) ((void far *) MAKELONG((ofs), (seg)))
  15.  
  16. BOOL dpmi_present(void)
  17. {
  18.     _asm mov ax, 1686h
  19.     _asm int 2fh
  20.     _asm not ax
  21. }
  22.  
  23. void dpmi_version(unsigned *pmaj, unsigned *pmin, 
  24.     unsigned *pflags, unsigned *pproc)
  25. {
  26.     unsigned char maj, min, proc;
  27.     unsigned flags;
  28.     _asm {
  29.         mov ax, 0400h
  30.         int 31h
  31.         mov maj, ah
  32.         mov min, al
  33.         mov flags, bx
  34.         mov proc, cl
  35.         }
  36.     *pmaj = maj;
  37.     *pmin = min;
  38.     *pflags = flags;
  39.     *pproc = proc;
  40. }
  41.  
  42. /* Performs a real-mode interrupt from protected mode */
  43. BOOL dpmi_rmode_intr(unsigned intno, unsigned flags, 
  44.     unsigned copywords, RMODE_CALL far *rmode_call)
  45. {
  46.     if (flags) intno |= 0x100;
  47.     _asm {
  48.         push di
  49.         mov ax, 0300h       // simulate real-mode interrupt
  50.         mov bx, word ptr intno       // interrupt number, flags
  51.         mov cx, word ptr copywords  // words to copy from pmode to rmode stack
  52.         les di, dword ptr rmode_call  // ES:DI = addr of rmode call struct
  53.         int 31h             // call DPMI
  54.         jc error
  55.         mov ax, 1           // return TRUE
  56.         jmp short done
  57.         }
  58. error:  
  59.         _asm xor ax, ax     // return FALSE
  60. done:
  61.         _asm pop di
  62. }
  63.  
  64. /* Allocates a single protected-mode LDT selector */
  65. unsigned dpmi_sel(void)
  66. {
  67.     _asm {
  68.         xor ax, ax          // Allocate LDT Descriptors
  69.         mov cx, 1           // allocate just one
  70.         int 31h             // call DPMI
  71.         jc error
  72.         jmp short done      // AX holds new LDT selector
  73.         }
  74. error:  
  75.         _asm xor ax, ax     // failed
  76. done:;
  77. }
  78.  
  79. BOOL dpmi_set_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
  80. {
  81.     _asm {
  82.         push di
  83.         mov ax, 000ch       // Set Descriptor
  84.         mov bx, word ptr pmodesel    // protected mode selector
  85.         les di, dword ptr d // descriptor
  86.         int 31h             // call DPMI
  87.         jc error
  88.         mov ax, 1           // return TRUE
  89.         jmp short done
  90.         }
  91. error:  
  92.         _asm xor ax, ax     // return FALSE
  93. done:
  94.         _asm pop di
  95. }
  96.  
  97. BOOL dpmi_get_descriptor(unsigned pmodesel, DESCRIPTOR far *d)
  98. {
  99.     _asm {
  100.         push di
  101.         mov ax, 000bh       // Get Descriptor
  102.         mov bx, word ptr pmodesel    // protected mode selector
  103.         les di, dword ptr d // descriptor
  104.         int 31h             // call DPMI
  105.         jc error
  106.         mov ax, 1           // return TRUE
  107.         jmp short done
  108.         }
  109. error:  
  110.         _asm xor ax, ax     // return FALSE
  111. done:
  112.         _asm pop di
  113. }
  114.  
  115. BOOL dpmi_sel_free(unsigned pmodesel)
  116. {
  117.     _asm {
  118.         mov ax, 0001h       // Free LDT Descriptor
  119.         mov bx, word ptr pmodesel    // selector to free
  120.         int 31h             // call DPMI
  121.         jc error
  122.         mov ax, 1           // return TRUE
  123.         jmp short done
  124.         }
  125. error:  
  126.         _asm xor ax, ax     // return FALSE
  127. done:;
  128. }
  129.  
  130. /* Layer on top of DPMI and Windows services ******************************/
  131.  
  132. unsigned DosAllocRealSeg(DWORD bytes, unsigned *ppara, unsigned *psel)
  133. {
  134.     DWORD dw = GlobalDosAlloc(bytes);
  135.     if (dw == NULL) 
  136.         return 8;   /* insufficient memory */
  137.     *ppara = HIWORD(dw);
  138.     *psel = LOWORD(dw);
  139.     return 0;
  140. }
  141.  
  142. unsigned DosFreeRealSeg(unsigned sel)
  143. {
  144.     return (GlobalDosFree(sel) != NULL);
  145. }
  146.  
  147. /*
  148.     Use DPMI services to map a real-mode paragraph into protected-mode
  149.     address space. First we get a selector using the DPMI "Allocate
  150.     LDT Descriptors" call (INT 31h Function 0000h), via our dpmi_sel()
  151.     function. We then get the descriptor for any old data segment in
  152.     our program so that it can be used as a template of sorts for the
  153.     new descriptor. This is done with the DPMI "Get Descriptor" call
  154.     (INT 31h Function 000Bh), via our dpmi_get_descriptor() function.
  155.     We then alter the descriptor to reflect the "rmpara" and "size"
  156.     requested, and finally associate the descriptor with our LDT
  157.     selector, using the DPMI "Set Descriptor" call (INT 31h Function
  158.     000Ch). All the user needs, of course, is the selector itself.
  159. */
  160. unsigned DosMapRealSeg(unsigned rmpara, DWORD size, unsigned far *psel)
  161. {
  162.     DESCRIPTOR d;
  163.     unsigned long addr;
  164.     unsigned sel = dpmi_sel();
  165.     if (! sel) 
  166.         return 8;   /* insufficient memory */
  167.     /* make sure psel is valid */
  168.     if (! verw(FP_SEG(psel)))
  169.         return 490; /* invalid selector error */
  170.     /* get descriptor for any data segment */
  171.     dpmi_get_descriptor(FP_SEG(psel), &d);
  172.     d.limit = (unsigned) size - 1;
  173.     addr = ((unsigned long) rmpara) << 4L;
  174.     d.addr_lo = (unsigned) addr;
  175.     d.addr_hi = (unsigned char) (addr >> 16);
  176.     d.reserved = d.addr_xhi = 0;
  177.     dpmi_set_descriptor(sel, &d);
  178.     *psel = sel;
  179.     return 0;       /* success */
  180. }
  181.  
  182. unsigned DosFreeSeg(unsigned sel)
  183. {
  184.     return ! dpmi_sel_free(sel);
  185. }
  186.  
  187. /*
  188.     Use undocumented Windows function to retrieve the real-mode
  189.     equivalent to a protected mode pointer. Of course, we could also
  190.     have used dpmi_get_descriptor() here, but GetSelectorBase()
  191.     is slightly more convenient. If the base of the selector is
  192.     above the one-megabyte watershed, then there is no real-mode
  193.     equivalent, so we return NULL.
  194. */
  195. void far *DosProtToReal(void far *prot)
  196. {
  197.     unsigned long base = GetSelectorBase(FP_SEG(prot));
  198.     if (base > 0xFFFFFL)
  199.         return NULL;    /* not accessible in real mode */
  200.     else
  201.         return MAKEP(base >> 4, (base & 0x0F) + FP_OFF(prot));
  202. }
  203.  
  204. unsigned __0000H = 0;   /* undocumented Windows selector */
  205.  
  206. unsigned mapped = 0;    /* keep track of number of mapped selectors */
  207.  
  208. unsigned get_mapped(void)   { return mapped; }
  209.  
  210. /*
  211.     Map a real-mode pointer into our protected mode address space.
  212.     If the real-mode pointer is in the first 64k of memory, use the
  213.     undocumented Windows selector __0000H. Otherwise, use DPMI
  214.     services via our DosMapRealSeg() function, which provides a more
  215.     convenient layer on top of DPMI. This map_real() function in
  216.     turn provides a more convenient layer on top of DosMapRealSeg().
  217.     Note that DosMapRealSeg() takes a paragraph address, whereas
  218.     map_real takes a full segment:offset real-mode pointer. 
  219. */
  220. void far *map_real(void far *rptr, unsigned long size)
  221. {
  222.     unsigned seg, ofs, sel;
  223.     
  224.     if (! __0000H)  /* one time init: get undocumented Windows selector */
  225.         __0000H = LOWORD(GetProcAddress(GetModuleHandle("KERNEL"),"__0000H"));
  226.     
  227.     seg = FP_SEG(rptr);
  228.     ofs = FP_OFF(rptr);
  229.     if ((seg < 0x1000) && ((ofs + size) < 0xFFFF))
  230.         return MAKEP(__0000H, (seg << 4) + ofs);
  231.     if (DosMapRealSeg(seg, size + ofs, &sel) != 0)
  232.         return 0;
  233.     mapped++;
  234.     return MAKEP(sel, ofs); 
  235. }
  236.  
  237. void free_mapped_seg(void far *fp)
  238. {
  239.     unsigned sel = FP_SEG(fp);
  240.     if (sel == __0000H)
  241.         return;
  242.     if (DosFreeSeg(sel) == 0)
  243.         mapped--;
  244. }
  245.  
  246. /* Use Intel VERW instruction to validate pointers */
  247. unsigned verw(unsigned sel)
  248. {
  249.     _asm mov ax, 1
  250.     _asm verw sel
  251.     _asm je short ok
  252.     _asm xor ax, ax
  253. ok:;
  254. }
  255.